/*
 *  Copyright (C) 2010 Jonathan MERCIER <bioinfornatics@fedoraproject.org>,
 *  Louise-Amélie SCHMITT <louise-amelie.schmitt@etu.u-bordeaux1.fr>,
 *  Florence Maurier <florence_maurier@orange.fr>,
 *  Marianne Dussart <marianne.dussart@orange.fr>,
 *  Nicolas Fontaine <nifontaine@gmail.com>
 *
 *  JACoMode is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  JACoMode is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with JACoMode.  If not, see <http://www.gnu.org/licenses/>.
 */


package fr.ubdx1.jacomode.models;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Collections;
import org.apache.commons.collections.*;

public class Results
{
    private ArrayList<Integer>   efmByClass             ;   // number of efms in a class
    private ArrayList<Integer>   motifSizeByClass       ;   // motif size of a given class
    private ArrayList<String>    motif                  ;   // contains the motif of a class, from the first to the last class
    private ArrayList<Integer>   sizeOfMotif            ;   // contains the existing motif sizes
    private ArrayList<Integer>   nbClassByMotifSize     ;   // number of classes by motif size
    private ArrayList<String>    IDClassByMotifSize     ;   // list of classes by motif size
    private ArrayList<String>    listEfmByClass         ;   // efm list by class
    private ArrayList<String>    listEfmUsed            ;   // list of used efm
    private ArrayList<Integer>   IDEfm                  ;   // list of non-redundant used efm in ascending order
    private ArrayList<Integer>   efmOccurence           ;   // efm repeats list
    private ArrayList<String> emflocation            ;   // efm location a retirer
    private ArrayList<String>    efmlocationtest        ;// list of location for one efm, need association with mhm
    private MultiMap             mhm                    ;// MultiHashMap to stock efm's location, must be associed with efmlocation

    private int                  nbtotalClass           ;   // total number of classes (motifs)
    private int                  totalefm               ;   // total number of efm
    private int                  meanMotifSize          ;   // mean motif size
    private int                  meanClassSize          ;   // mean efm number by class
    private int                  nbOfDifferentMotifSize ;   // total number of motif sizes
    private int                  noise                  ;   // noise

    public Results()
    {
        System.out.println("Création de l'objet");
        efmByClass              = new ArrayList<Integer>();
        motifSizeByClass        = new ArrayList<Integer>();
        motif                   = new ArrayList<String>();
        sizeOfMotif             = new ArrayList<Integer>();
        nbClassByMotifSize      = new ArrayList<Integer>();
        IDClassByMotifSize      = new ArrayList<String>();
        listEfmByClass          = new ArrayList<String>();
        listEfmUsed             = new ArrayList<String>();
        IDEfm                   = new ArrayList<Integer>();
        efmOccurence            = new ArrayList<Integer>();
        emflocation             = new ArrayList<String>();
        efmlocationtest= new ArrayList<String>();
        mhm = new MultiHashMap();

        nbtotalClass            = 0;
        totalefm                = 0;
        meanMotifSize           = 0;
        meanClassSize           = 0;
        nbOfDifferentMotifSize  = 0;
        noise                   = 0;
    }

    public void parse(String path)
    {
        System.out.println("Parsing");
        //path is the path of the files generated by ACoM
        Scanner s               = null;
        String  bl              = "";
        int     MotifSize       = 0;
        int     sumOfMotifSize  = 0;
        boolean balise          = false;
        String  pathclass       = "";
        String  motifstring2    = "";
        String  string1         = ":";
        String  string2         = "=";
        String  string3         = "NB_noise";
        String  motifstring     = "";
        String  listeEfm        = "";
        String  efmloca         = "";
        Pattern p1              = Pattern.compile(string1);
        Pattern p2              = Pattern.compile(string2);
        Pattern p3              = Pattern.compile(string3);
        int     indiceparent    = 0;
        int     i;
        ArrayList<Integer>   motifBySize         = new ArrayList<Integer>(); // sorts motifSizeByClass to make a non-redundant list, sizeOfMotif

        // analysis of the motifs : the number of existing classes, the number of efm by class, a class' motif size,
        //the total number of efm, the mean number of efm by class, the mean motif size
        try
        {
            if (! path.endsWith("/") )
                path += "/";
            s = new Scanner(new BufferedReader(new FileReader(( path +"motif.txt" ) ) ) );
        }
        catch(IOException error)
        {
            error.printStackTrace();
        }
        finally
	{
            while ( s.hasNext() )
            {
                bl= s.next();
                Matcher m1 = p1.matcher(bl);
                boolean b1 = m1.matches();
                Matcher m2 = p2.matcher(bl);
                boolean b2 = m2.matches();
                Matcher m3 = p3.matcher(bl);
                boolean b3 = m3.matches();
                if (b1)
                {
                    nbtotalClass++;
                    balise= true;
                }
                else if (b2)
                {
                    bl= s.next();
                    i = Integer.parseInt(bl);
                    totalefm=totalefm+i;
                    efmByClass.add(i);// the number of efm by class
                    balise= false;
                    MotifSize=MotifSize-2;
                    if (MotifSize!=-2)
                    {
                        sumOfMotifSize=sumOfMotifSize+MotifSize;
                    }
                    if( motifstring.length()!=0)
                    {
                        motifstring2=motifstring.substring(3,motifstring.length()-20);
                    }
                    motif.add(motifstring2);
                    motifstring="";
                    motifSizeByClass.add(MotifSize);// a class' motif size
                    MotifSize=0;
                }
                if (balise)
                {
                    MotifSize=MotifSize+1;
                    motifstring=motifstring+" "+bl;
                }
                else if (b3)
                {
                    bl= s.next();
                    bl= s.next();
                    noise=Integer.parseInt(bl);
                    System.out.println(noise);
                }
            }
            if (s != null)
            {
                s.close();
            }
	}
        meanClassSize=totalefm/nbtotalClass;
        meanMotifSize=sumOfMotifSize/nbtotalClass;


        System.out.println("motifSizeByClass: " + efmByClass.size());
        for(int k = 0; k < efmByClass.size(); k++)
        {
            motifBySize.add(motifSizeByClass.get(k));
            System.out.println("num "+k+" "+efmByClass.get(k));
        }

        //  the number of efm for an existing motif size
        Collections.sort(motifBySize);

        indiceparent=motifBySize.get(0);
        sizeOfMotif.add(indiceparent);
       // System.out.println("sizeOfMotif: " + efmByClass.size());
        for(int p = 0; p < motifBySize.size(); p++)
        {
        if (indiceparent!=motifBySize.get(p))
            {
                sizeOfMotif.add(motifBySize.get(p));
                indiceparent=motifBySize.get(p);
            }
        }

        //number of classes for a motif size and which class is associated with which motif size
        for(int p = 0; p < sizeOfMotif.size(); p++)
        {
            int nbclass=0;
            String classe="";
        //System.out.println("sizeOfMotif: " + efmByClass.size());
            for(int k = 0; k < efmByClass.size(); k++)
            {
                if (sizeOfMotif.get(p).equals(motifSizeByClass.get(k)))
                {
                    nbclass=nbclass+1;
                    classe=classe+" "+(k+1);

                }
            }
            nbClassByMotifSize.add(nbclass);
            IDClassByMotifSize.add(classe);
        }
        nbOfDifferentMotifSize=nbClassByMotifSize.size();

        // analysis of the classes to determine  : the efm/classes; the used efm; the efm repeats, the efm's location
        int c  = 0;
        for(int numclass = 1; numclass < nbtotalClass+1; numclass++)
        {
            s           = null;
            pathclass   = path+"class"+ numclass+".txt";
            System.out.println("class: " + pathclass);
            listeEfm    = "";
            try
            {
                s = new Scanner(new BufferedReader(new FileReader(pathclass)));
            }
            catch(IOException error)
            {
                error.printStackTrace();
            }
            finally
            {
                s.nextLine();
                c          = 0;
                String id   = "";
                while (s.hasNextLine())
                {
                    bl      = "";
                    bl      = s.nextLine();
                    c       = bl.indexOf(":",1);
                    id      = bl.substring(0,c);
                    listeEfm= listeEfm+" "+id;
                    listEfmUsed.add(id);
                }
                if (s != null)
                {
                    s.close();
                }
            }
            listEfmByClass.add(listeEfm);
        }
        /*
        Collections.sort(listEfmUsed);
        String indiceparen  = listEfmUsed.get(0);
        int d               = Integer.parseInt(indiceparen);
        IDEfm.add(d);
        int occu=0;
        System.out.println("IDEfm: " + efmByClass.size());
        for(int p = 0; p < listEfmUsed.size(); p++)
        {
            occu=1;
            if (!indiceparen.equals(listEfmUsed.get(p)))
            {
                IDEfm.add(Integer.parseInt(listEfmUsed.get(p)));
                indiceparen=listEfmUsed.get(p);
            }
            if (indiceparen.equals(listEfmUsed.get(p)))
            		{
                		occu++;
            		}
		    efmOccurence.add(occu);

        }
         */
        Collections.sort(listEfmUsed);
        ArrayList<Integer> EfmUsed= new ArrayList<Integer>();
        for(int p = 0; p < listEfmUsed.size(); p++)
        {
            EfmUsed.add(Integer.parseInt(listEfmUsed.get(p)));
        }
        Collections.sort(EfmUsed);
        int indiceparen  = EfmUsed.get(0);
        IDEfm.add(indiceparen);
        int occu=0;
        System.out.println("efmoccurence");
        for(int p = 0; p < EfmUsed.size(); p++)
        {
            if (indiceparen!=(EfmUsed.get(p)))
            {
                efmOccurence.add(occu);
                IDEfm.add(EfmUsed.get(p));
                indiceparen=EfmUsed.get(p);
                occu=0;
            }
            if (indiceparen==(EfmUsed.get(p)))
            {
                occu++;
            }
            if (p==(EfmUsed.size()-1))
            {
                efmOccurence.add(occu);
            }
        }
        Collections.sort(IDEfm);
        System.out.println("efmloca ");
        String key="";
        for(int bn = 0; bn < listEfmByClass.size(); bn++)
            {
                
                try
                {
                    s = new Scanner(listEfmByClass.get(bn));
                }
                finally
                {
                    while (s.hasNext())
                    {
                        bl=s.next();
                        key=bl;
                        efmloca= (bn+1)+"";
                        mhm.put(key, efmloca);

                    }
                }
            }
        ArrayList<String> list = new ArrayList<String>();
        String classe=null;
        for(int bn = 0; bn < IDEfm.size(); bn++)
        {
            list=null;
            String cle=Integer.toString(IDEfm.get(bn));
            list=getEfmlocationtest(cle);
            classe=""+list;
            int leng=classe.length();
            classe=" classe: "+classe.substring(1,leng-1);
            emflocation.add(classe);

        }
        System.out.println("emflocation FIN");

       
    }




 

    // writing the CSV file
    public void csvResult(int sigma,int epsilon, String path, int num) throws IOException
	{
        if (! path.endsWith("/") )
                path += "/";

		File file = new File(path+"Result" + num + ".csv");
		FileWriter fw;
		fw = new FileWriter(file);
		int totalClass= getNbtotalClass();
		String str="Results"+"\n";

		fw.write(str);
        fw.write("\n");
        fw.write("sigma, epsilon"+"\n");
        fw.write(Integer.toString(sigma)+", "+Integer.toString(epsilon)+"\n");
		fw.write("\n");
		fw.write("Global stats"+"\n");

		fw.write("\n");
		fw.write("total class, average efm by class, total efm, noise effective"+"\n");
		fw.write(Integer.toString(totalClass)+", "+Integer.toString(getMeanClassSize())+", "+getTotalefm()+", "+getNoise()+"\n");
		fw.write("\n");
		fw.write("class, NB_elementary_modes"+"\n");
		ArrayList<Integer> nb_efms = new ArrayList<Integer>();
		nb_efms=getEfmByClass();
		for (int x = 0; x < nb_efms.size(); x++)
		{
			fw.write("class "+(x+1)+", "+Integer.toString(nb_efms.get(x))+"\n");
		}
		fw.write("\n");

		fw.write("number of motifs size, average motifs size"+"\n");
		fw.write(getNbOfDifferentMotifSize()+", "+getMeanMotifSize()+"\n");
		fw.write("\n");
		fw.write("\n");
		fw.write("\n");
		fw.write("Analysis of motifs"+"\n");
		fw.write("\n");
		ArrayList<Integer> nbre_motifs=new ArrayList<Integer>();
		nbre_motifs=getNbClassByMotifSize();
		fw.write("motifs size,number of class,id of class"+"\n");
		for (int x = 0; x < nbre_motifs.size(); x++)
		{
			fw.write(getSizeOfMotif().get(x)+", "+nbre_motifs.get(x)+", "+getIDClassByMotifSize().get(x)+"\n");

		}
		fw.write("\n");
		fw.write("\n");
		fw.write("Analysis of efms"+"\n");
		fw.write("\n");
		fw.write("id efm, occurence, location"+"\n");
		ArrayList<Integer> id_efm=new ArrayList<Integer>();
		id_efm=getIDEfm();
        System.err.println(id_efm.size());
		for (int x = 0; x < id_efm.size(); x++)
		{
            //System.out.println(x);
           // System.out.println(id_efm.get(x)+", "+getEfmOccurence().get(x)+", "+getEfmLocation().get(x));
			fw.write(id_efm.get(x)+", "+getEfmOccurence().get(x)+", "+getEfmLocation().get(x)+"\n");

		}

		fw.close();
	}

    // getters
    public ArrayList<Integer> getEfmByClass()
    {
        return efmByClass;
    }
    public ArrayList<Integer> getMotifSizeByClass()
    {
        return motifSizeByClass;
    }
    public ArrayList<String> getMotif()
    {
        return motif;
    }

    public ArrayList<Integer> getSizeOfMotif()
    {
        return sizeOfMotif;
    }

    public ArrayList<Integer> getNbClassByMotifSize()
    {
        return nbClassByMotifSize;
    }

    public ArrayList<String> getIDClassByMotifSize()
    {
        return IDClassByMotifSize;
    }

    public ArrayList<String> getListEfmByClass()
    {
        return listEfmByClass;
    }

    public ArrayList<String> getListEfmUsed()
    {
        return listEfmUsed;
    }

    public ArrayList<Integer> getIDEfm()
    {
        return IDEfm;
    }

    public ArrayList<Integer> getEfmOccurence()
    {
        return efmOccurence;
    }

    public ArrayList<String> getEfmLocation()
    {
        return emflocation;
    }
    public int getNbtotalClass()
    {
        return nbtotalClass;
    }

    public int getMeanClassSize()
    {
        return meanClassSize;
    }
    public int getMeanMotifSize()
    {
	return meanMotifSize;
    }

    public int getTotalefm()
    {
        return totalefm;
    }
    public int getNbOfDifferentMotifSize()
    {
        return nbOfDifferentMotifSize;
    }
    public int getNoise()
    {
        return noise;
    }
    private ArrayList<String> getEfmlocationtest(String cle)
    {
            efmlocationtest = (ArrayList) mhm.get(cle);
            return efmlocationtest;
    }
}